package com.cgnpc.scp.common.service;

import cn.com.cgnpc.aep.bizcenter.appcenter.sdk.client.RestClient;
import com.cgnpc.cud.boot.autoconfigure.aep.AepProperties;
import com.cgnpc.scp.common.bean.CustomDownloadFileInputStreamResource;
import com.cgnpc.scp.common.bean.CustomDownloadFileResourceHttpMessageConverter;
import com.cgnpc.scp.common.utils.FileUtil;
import com.cgnpc.scp.common.utils.IOUtil;
import com.cgnpc.scp.common.utils.MediaTypeUtil;
import com.cgnpc.scp.common.utils.StringUtil;
import com.cgnpc.scp.common.utils.UrlUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * 下载文件服务类
 */
@Service
public class DownloadFileService {
    private static final Logger LOGGER = LoggerFactory.getLogger(DownloadFileService.class);

    @Autowired
    public CustomDownloadFileResourceHttpMessageConverter customDownloadFileResourceHttpMessageConverter;

    @Autowired
    private MessageSource messageSource;

    @Autowired
    private AepProperties aepProperties;

    @Autowired
    private RestClient restClient;

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 下载附件先重置HttpServletResponse
     *
     * @param response     HttpServletResponse
     * @param fileRealName 文件名称
     * @throws Exception error
     */
    public void resetResponseWithAttachmentUTF8(
            HttpServletResponse response
            , String fileRealName
    ) throws Exception {
        Long fileLength = null;
        resetResponseWithAttachmentUTF8(response, fileRealName, fileLength);
    }

    /**
     * 下载附件先重置HttpServletResponse
     *
     * @param response     HttpServletResponse
     * @param fileRealName 文件名称
     * @param fileLength   文件大小，不传递值为null
     * @throws Exception error
     */
    public void resetResponseWithAttachmentUTF8(
            HttpServletResponse response
            , String fileRealName
            , Long fileLength
    ) throws Exception {
        response.reset();
        response.setCharacterEncoding(StringUtil.CHARSET_UTF8);
        response.setContentType(MediaTypeUtil.APPLICATION_OCTET_STREAM_UTF8_VALUE);
        // response.setHeader("Content-disposition", "attachment; filename=" + new String(fileRealName.getBytes(StringUtil.CHARSET_UTF8), StringUtil.CHARSET_ISO8859_1));
        // response.setHeader("Content-disposition", "attachment; filename=" + new String(fileRealName.getBytes(StringUtil.CHARSET_UTF8)));
        response.setHeader("Content-disposition", "attachment; filename=" + UrlUtil.urlEncodeWithUTF8(fileRealName));

        if (fileLength != null) {
            response.addHeader("Content-Length", "" + fileLength);
        }
    }

    /**
     * 下载文件
     *
     * @param request                request
     * @param response               response
     * @param httpFileUrlWithRequest 文件的地址
     * @param fileNameWithResponse   下载的文件名称
     */
    public void downloadFile(
            HttpServletRequest request,
            HttpServletResponse response,
            String httpFileUrlWithRequest,
            String fileNameWithResponse
    ) {
        final String logInfo = "[downloadFile_UUID_" + UUID.randomUUID().toString() + "]";
        FileInputStream localFileInputStream = null;

        try {
            // String fileNameWithResponse = "test" + UUID.randomUUID().toString() + ".tar.gz";
            List<MediaType> acceptMediaTypeList = new ArrayList<>();
            acceptMediaTypeList.add(MediaType.ALL);

            HttpHeaders httpHeaders = new HttpHeaders();
            httpHeaders.setAccept(acceptMediaTypeList);

            HttpEntity<Object> httpEntity = new HttpEntity<>(httpHeaders);

            Map<String, ?> uriVariables = new HashMap<>();

            // uriVariables.put("ids", strIds);

//            // begin 使用字节数组能下载文件;success;
//            Class<byte[]> responseType = byte[].class;
//            ResponseEntity<byte[]> responseEntity = restTemplate.exchange(
//                    fileUrl,
//                    HttpMethod.GET,
//                    httpEntity,
//                    responseType,
//                    uriVariables
//            );
//
//            HttpStatus responseEntityStatusCode = responseEntity.getStatusCode();
//            HttpHeaders responseEntityHeaders = responseEntity.getHeaders();
//            byte[] responseEntityBody = responseEntity.getBody();
//            // end 使用字节数组能下载文件;success;

            // begin 使用自定义的转换器获取LocalFile;success;
            if (!restTemplate.getMessageConverters().contains(customDownloadFileResourceHttpMessageConverter)) {
                restTemplate.getMessageConverters().add(0, customDownloadFileResourceHttpMessageConverter);
            }

            ResponseEntity<CustomDownloadFileInputStreamResource> responseEntity = restTemplate.exchange(
                    httpFileUrlWithRequest,
                    HttpMethod.GET,
                    httpEntity,
                    CustomDownloadFileInputStreamResource.class,
                    uriVariables
            );

//            HttpStatus responseEntityStatusCode = responseEntity.getStatusCode();
//            HttpHeaders responseEntityHeaders = responseEntity.getHeaders();
            CustomDownloadFileInputStreamResource responseEntityBody = responseEntity.getBody();
            File localTempFile = responseEntityBody.getFile();
            // end 使用自定义的转换器获取LocalFile;success;

            // begin 安全校验，使用文件校验相关路径
            localTempFile = FileUtil.formatSafeFileWithDownloadFile(localTempFile);
            // end 安全校验，使用文件校验相关路径

            if (localTempFile == null) {
                LOGGER.error("{}localTempFile is null;", logInfo);
                return;
            }

            this.resetResponseWithAttachmentUTF8(response, fileNameWithResponse);
            ServletOutputStream servletOutputStream = response.getOutputStream();

            localFileInputStream = new FileInputStream(localTempFile);
            byte[] arrReadData = new byte[1024 * 1024 * 2];
            int readLen = 0;

            while ((readLen = localFileInputStream.read(arrReadData)) != -1) {
                servletOutputStream.write(arrReadData, 0, readLen);
                servletOutputStream.flush();
            }

            // Close the streams
            servletOutputStream.flush();
            servletOutputStream.close();
            localFileInputStream.close();

        } catch (Exception e) {
            LOGGER.error("{}error;", logInfo, e);
            throw new RuntimeException(e);
        } finally {
            IOUtil.closeStream(localFileInputStream);
        }
    }

}
